home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / vg-2.03 / video / v86mode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  13.1 KB  |  599 lines

  1. /*
  2.  * Copyright (C) 1990-1992 Michael Davidson.
  3.  * All rights reserved.
  4.  *
  5.  * Permission to use, copy, modify, and distribute this software
  6.  * and its documentation for any purpose and without fee is hereby
  7.  * granted, provided that the above copyright notice appear in all
  8.  * copies and that both that copyright notice and this permission
  9.  * notice appear in supporting documentation.
  10.  *
  11.  * This software is provided "as is" without express or implied warranty.
  12.  */
  13.  
  14. #include    <stdio.h>
  15. #include    <stdarg.h>
  16. #include    <memory.h>
  17. #include    <errno.h>
  18. #include    <unistd.h>
  19. #include    <sys/param.h>
  20. #include    <sys/seg.h>
  21. #include    <sys/types.h>
  22. #include    <sys/immu.h>
  23. #include    <sys/region.h>
  24. #include    <sys/proc.h>
  25. #include    <sys/tss.h>
  26. #include    <sys/v86.h>
  27. #include    <sys/sysi86.h>
  28. #include    <sys/cram.h>
  29.  
  30. #include    "v86mode.h"
  31. #include    "io.h"
  32.  
  33. #define    DEBUG(x)    
  34. #define    V86_IO_DEBUG    1
  35.  
  36. /*
  37.  * V86 mode TSS
  38.  */
  39. struct tss386            *v86tss;
  40.  
  41. /*
  42.  * V86 mode extended TSS
  43.  */
  44. static struct v86xtss        *xtss;
  45.  
  46. /*
  47.  * V86 mode i/o permission bitmap
  48.  *
  49.  * v86init() requires that the xtss structure including
  50.  * the i/o bitmap be contained within a single 4K page.
  51.  * TSS_IO_BITMAP_SIZE is 0x80 which allows i/o addresses
  52.  * up to 0x3ff to be handled directly through the TSS.
  53.  * i/o accesses above 0x3ff always trap into the V86
  54.  * instruction emulation code which uses a full 8K bitmap
  55.  * to keep track of the entire 16 bit i/o space.
  56.  */
  57. #define    MAX_IO_ADDR        0xffff
  58. #define    IO_BITMAP_SIZE        8192
  59.  
  60. #define    TSS_MAX_IO_ADDR        0x3ff
  61. #define TSS_IO_BITMAP_SIZE    ((TSS_MAX_IO_ADDR + 8) / 8)
  62.  
  63. static unsigned char        *io_bitmap;
  64.  
  65. /*
  66.  * magic location used for cli/sti and pushf/popf emulation
  67.  */
  68. #define    VIRTUAL_FLAGS    (*(unsigned int *)0xF4200)
  69.  
  70. /*
  71.  * V86Init() - initialise the v86 environment
  72.  */
  73. int
  74. V86Init()
  75. {
  76.     struct v86parm    v86parms;
  77.     int            i;
  78.  
  79. /*
  80.  * set up parameters for v86init()
  81.  */
  82.     v86parms.magic[0]    = V86_MAGIC0;
  83.     v86parms.magic[1]    = V86_MAGIC1;
  84.     v86parms.xtssp    = 0;
  85. #if !defined(SVR4)
  86.     v86parms.xtss_off    = 0;
  87. #endif
  88.     v86parms.szxtss    = sizeof(struct v86xtss);
  89.     v86parms.szbitmap    = TSS_IO_BITMAP_SIZE + 1;
  90.  
  91.     if (sysi86(SI86V86, V86SC_INIT, &v86parms) != 0)
  92.     return -1;
  93.  
  94.     /*
  95.      * v86init() returns a pointer to the xtss structure
  96.      */
  97.     xtss    = v86parms.xtssp;
  98.     v86tss    = &xtss->xt_tss;
  99.  
  100.     /*
  101.      * set up fields in the xtss that are used by the kernel
  102.      * emulation code
  103.      */
  104.  
  105.     /*
  106.      * this is the location that will be used by the kernel
  107.      * for cli/sti/popf emulation to keep track of the state
  108.      * of the interrupt mask bit in the flags register
  109.      */
  110.     xtss->xt_vflptr    = &VIRTUAL_FLAGS;
  111.  
  112.     /*
  113.      * xt_vimask, xt_vitoect and xt_viflag are bitmasks used by the
  114.      * kernel for exception handling as follows
  115.      *
  116.      * xt_vimask    is set in user mode and read by the kernel
  117.      *            it defines which exceptions will wake up
  118.      *            a process sleeping in v86sleep()
  119.      * xt_vitoect    is set in user mode and read by the kernel
  120.      *            it defines which exceptions should cause a
  121.      *            task switch to 386 mode
  122.      * xt_viflag    is set by the kernel and cleared in user mode
  123.      *            it defines which exceptions are currently pending
  124.      */
  125.  
  126.     /*
  127.      * not using v86sleep() so set vi_mask to V86VI_NONE
  128.      */
  129.     xtss->xt_vimask    = V86VI_NONE;
  130.  
  131.     /*
  132.      * switch to 386 mode to handle processor traps in V86 mode and
  133.      * signals that arrive when running in V86 mode
  134.      */
  135.     xtss->xt_vitoect    = V86VI_DIV0        /* divide by 0        */
  136.             | V86VI_SGLSTP        /* single step        */
  137.             | V86VI_BRKPT        /* breakpoint        */
  138.             | V86VI_OVERFLOW    /* overflow        */
  139.             | V86VI_BOUND        /* bounds trap        */
  140.             | V86VI_INVOP        /* illegal instruction    */
  141.             | V86VI_SIGHDL;        /* signal pending    */
  142.  
  143.     /*
  144.      * xt_imaskbits is a bitmap of 256 bits that define whether
  145.      * particular 8086 software interrupts should be emulated
  146.      * by the kernel general protection trap handler or should
  147.      * trap to user mode emulation. Bits set to 0 are directly
  148.      * emulated in the kernel, bits set to 1 cause a task switch
  149.      * to 386 mode for emulation
  150.      */
  151.     for (i = 0; i < V86_IMASKBITS; i++)
  152. #if 0
  153.     xtss->xt_imaskbits[i]    = 0;    
  154. #else
  155.     xtss->xt_imaskbits[i]    = 0xffffffff;    
  156. #endif
  157.  
  158.     xtss->xt_tss.t_bitmapbase    = v86parms.szxtss << 16;
  159.     io_bitmap            = (unsigned char *)xtss + v86parms.szxtss;
  160.     memset(io_bitmap, 0xff, IO_BITMAP_SIZE + 1);
  161.  
  162.     return 0;
  163. }
  164.  
  165. /*
  166.  * V86MemMap() - map physical addresses into the V86 address space
  167.  */
  168. V86MemMap(
  169.     paddr_t    phys,
  170.     caddr_t    virt,
  171.     int        len
  172.     )
  173. {
  174.     struct v86memory    v86mem;
  175.  
  176.     v86mem.vmem_cmd    = V86MEM_MAP;
  177.     v86mem.vmem_physaddr= phys;
  178.     v86mem.vmem_membase    = virt;
  179.     v86mem.vmem_memlen    = len;
  180.     return sysi86(SI86V86, V86SC_MEMFUNC, &v86mem);
  181. }
  182.  
  183. /*
  184.  * V86MemUnmap() - unmap physical addresses from the V86 address space
  185.  */
  186. V86MemUnmap(
  187.     paddr_t    phys,
  188.     caddr_t    virt,
  189.     int        len
  190.     )
  191. {
  192.     struct v86memory    v86mem;
  193.  
  194.     v86mem.vmem_cmd    = V86MEM_UNMAP;
  195.     v86mem.vmem_physaddr= phys;
  196.     v86mem.vmem_membase    = virt;
  197.     v86mem.vmem_memlen    = len;
  198.     return sysi86(SI86V86, V86SC_MEMFUNC, &v86mem);
  199. }
  200.  
  201. /*
  202.  * V86IOEnable()    - enable a range of i/o addresses
  203.  */
  204. V86IOEnable(
  205.     unsigned    ioaddr,
  206.     int        n
  207.     )
  208. {
  209.     if ((ioaddr + n) > MAX_IO_ADDR)
  210.     return -1;
  211.  
  212.     while (--n >= 0)
  213.     {
  214.     int    index    = ioaddr >> 3;
  215.     int    mask    = ~(1 << (ioaddr & 7));
  216.  
  217.     io_bitmap[index] &= mask;
  218.     ioaddr++;
  219.     }
  220.  
  221.     return 0;
  222. }
  223.  
  224. /*
  225.  * V86IODisable()    - disable a range of i/o addresses
  226.  */
  227. V86IODisable(
  228.     unsigned    ioaddr,
  229.     int        n
  230.     )
  231. {
  232.     if ((ioaddr + n) > MAX_IO_ADDR)
  233.     return -1;
  234.  
  235.     while (--n >= 0)
  236.     {
  237.     int    index    = ioaddr >> 3;
  238.     int    mask    = 1 << (ioaddr & 7);
  239.  
  240.     io_bitmap[index] |= mask;
  241.     ioaddr++;
  242.     }
  243.  
  244.     return 0;
  245. }
  246.  
  247. /*
  248.  * IOEnabled() is a macro which checks the i/o bitmap for permission
  249.  * to make a byte, word or dword access to i/o space.
  250.  * It always fetches an unsigned short from the i/o bitmap (ie 2 bytes)
  251.  * so it may access one byte beyond the end of the real bitmap - this
  252.  * is OK since it is exactly the same mechanism used by the processor
  253.  * itself when checking the i/o bitmap in the TSS. The i/o bitmap
  254.  * is allocated with an extra byte at the end set to 0xff to catch any
  255.  * attempts to access off the end of i/o address space.
  256.  */
  257.  
  258. #define    IOEnabled(addr, mask)    ! ( *(unsigned short *)(io_bitmap+(addr>>3)) \
  259.                    & (mask << (addr & 7)) )
  260.  
  261. #define    IO_BYTE_MASK        0x01
  262. #define    IO_WORD_MASK        0x03
  263. #define    IO_DWORD_MASK        0x0f
  264.  
  265. STATIC int    V86Exception();
  266. STATIC int    V86Emulate();
  267. STATIC int    V86IOEmulate(byte_t op, word_t io_addr);
  268. STATIC int    V86INTEmulate(unsigned vector);
  269.  
  270. /*
  271.  * V86Run()    - switch to V86 mode
  272.  */
  273. int
  274. V86Run()
  275. {
  276.     register struct v86xtss    *x    = xtss;
  277.     register struct tss386    *t    = v86tss;
  278.     int                stat;
  279.     int                EnterV86Mode();
  280.  
  281.     x->xt_timer_count    = 0;
  282.     x->xt_timer_bound    = 1000;
  283.     x->xt_viflag    = 0;    /* clear any old exception flags    */
  284.  
  285.     do
  286.     {
  287.     x->xt_magicstat    = XT_MSTAT_PROCESS;
  288.  
  289.     EnterV86Mode();
  290.  
  291.     stat        = x->xt_magicstat;
  292.     x->xt_magicstat    = XT_MSTAT_NOPROCESS;
  293.  
  294.     if (stat == XT_MSTAT_OPSAVED)
  295.         *(byte_t *)((CS(t) << 4) + IP(t)) = x->xt_magictrap;
  296.  
  297.     /*
  298.      * check if there are any exceptions that we care about
  299.      */
  300.     if (x->xt_viflag & x->xt_vitoect)
  301.         stat = V86Exception();
  302.     else
  303.         stat = V86Emulate();
  304.  
  305.     } while (stat == 0);
  306.  
  307.     return stat;
  308. }
  309.  
  310.  
  311. /*
  312.  * V86Exception()    - handle V86 mode exceptions
  313.  */
  314. STATIC int
  315. V86Exception()
  316. {
  317.     register struct v86xtss    *x    = xtss;
  318.     int                viflag;
  319.  
  320.     if (x->xt_viflag & V86VI_SIGHDL)    /* signal handler    */
  321.     {
  322.     x->xt_viflag &= ~V86VI_SIGHDL;
  323.     (*x->xt_hdlr)(x->xt_signo);
  324.     /*
  325.      * set xt_signo to 0 to tell the kernel that there
  326.      * is no longer a pending signal
  327.      */
  328.     x->xt_signo    = 0;
  329.     }
  330.  
  331.     if ((viflag = x->xt_viflag & x->xt_vitoect) == 0)
  332.     return 0;
  333.  
  334.     if (viflag & V86VI_DIV0)
  335.     return ERR_V86_DIV0;
  336.  
  337.     if (viflag & V86VI_SGLSTP)
  338.     return ERR_V86_SGLSTP;
  339.  
  340.     if (viflag & V86VI_BRKPT)
  341.     return ERR_V86_BRKPT;
  342.  
  343.     if (viflag & V86VI_OVERFLOW)
  344.     return ERR_V86_OVERFLOW;
  345.  
  346.     if (viflag & V86VI_BOUND)
  347.     return ERR_V86_BOUND;
  348.  
  349.     if (viflag & V86VI_INVOP)
  350.     return ERR_V86_ILLEGAL_OP;
  351.  
  352.     return -1;
  353. }
  354.  
  355. /*
  356.  * V86Emulate()        - called to handle emulation of instructions
  357.  *              that could not be directly executed in V86 mode
  358.  *
  359.  *              also handles the emulation of i/o accesses to i/o
  360.  *              addresses beyond the limit (0x3ff) of the i/o
  361.  *              bitmap in the TSS.
  362.  */
  363. STATIC int
  364. V86Emulate()
  365. {
  366.     register struct tss386    *t    = v86tss;
  367.     byte_t            *codeseg;
  368.     word_t            ip;
  369.     byte_t            op;
  370.     word_t            io_addr;
  371.     unsigned            vector;
  372.     byte_t            *sp;
  373.  
  374.     codeseg    = (byte_t *)(CS(t) << 4);
  375.     ip        = IP(t);
  376.  
  377.     switch (op = codeseg[ip++])
  378.     {
  379.     case 0xe4:        /*    in    al, imm8    */
  380.     case 0xec:        /*    in    al, dx        */
  381.         io_addr = (op & 0x08) ? DX(t) : codeseg[ip++];
  382.         DEBUG((V86_IO_DEBUG, "inb(0x%x)\n", io_addr));
  383.         if (IOEnabled(io_addr, IO_BYTE_MASK))
  384.         AL(t) = inb(io_addr);
  385.         else if (! V86IOEmulate(op, io_addr))
  386.         return ERR_V86_ILLEGAL_IO;
  387.         break;
  388.  
  389.     case 0xe5:        /*    in    ax, imm8    */
  390.     case 0xed:        /*    in    ax, dx        */
  391.         io_addr = (op & 0x08) ? DX(t) : codeseg[ip++];
  392.         DEBUG((V86_IO_DEBUG, "inw(0x%x)\n", io_addr));
  393.         if (IOEnabled(io_addr, IO_WORD_MASK))
  394.         AX(t) = inw(io_addr);
  395.         else if (! V86IOEmulate(op, io_addr))
  396.         return ERR_V86_ILLEGAL_IO;
  397.         break;
  398.  
  399.     case 0xe6:        /*    out    imm8, al    */
  400.     case 0xee:        /*    out    dx, al        */
  401.         io_addr = (op & 0x08) ? DX(t) : codeseg[ip++];
  402.         DEBUG((V86_IO_DEBUG, "outb(0x%x, 0x%x)\n", io_addr, AL(t)));
  403.         if (IOEnabled(io_addr, IO_BYTE_MASK))
  404.         outb(io_addr, AL(t));
  405.         else if (! V86IOEmulate(op, io_addr))
  406.         return ERR_V86_ILLEGAL_IO;
  407.         break;
  408.  
  409.     case 0xe7:        /*    out    imm8, [e]ax    */
  410.     case 0xef:        /*    out    dx, [e]ax    */
  411.         io_addr = (op & 0x08) ? DX(t) : codeseg[ip++];
  412.         DEBUG((V86_IO_DEBUG, "outw(0x%x, 0x%x)\n", io_addr, AX(t)));
  413.         if (IOEnabled(io_addr, IO_WORD_MASK))
  414.         outw(io_addr, AX(t));
  415.         else if (! V86IOEmulate(op, io_addr))
  416.         return ERR_V86_ILLEGAL_IO;
  417.         break;
  418.  
  419.     case 0xcd:        /*    int    N        */
  420.         vector    = codeseg[ip++];
  421.         SP(t)    -= 6;
  422.         sp        = (byte_t *) ((SS(t) << 4) + SP(t));
  423.         *(word_t *) (sp + 4)    = FL(t);
  424.         *(word_t *) (sp + 2)    = CS(t);
  425.         *(word_t *) (sp + 0)    = ip;
  426.         vector    *= 4;
  427.         ip        = *(word_t *)vector;
  428.         CS(t)    = *(word_t *)(vector+2);
  429.         break;
  430.  
  431.     case 0xf4:        /* hlt                */
  432.         return ERR_V86_HALT;
  433.  
  434.     default:
  435.         return ERR_V86_ILLEGAL_OP;
  436.     } /* end opcode switch */
  437.  
  438.     /*
  439.      * since everything was emulated OK update IP in the TSS
  440.      * and return 0 to indicate that it is OK to go back to
  441.      * V86 mode
  442.      */
  443.  
  444.     IP(t)    = ip;
  445.     return 0;
  446. }
  447.  
  448. /*
  449.  * V86IOEmulate()    - i/o emulation
  450.  *
  451.  *              this is the common handler for all
  452.  *              illegal i/o requests
  453.  *
  454.  *              silently ignore attempts to send a non-specific
  455.  *              EIO command to the master PIC (ATI VGAWonder
  456.  *              BIOS does this ....)
  457.  *
  458.  *              fail all other i/o requests
  459.  */
  460.  
  461. #define    IO_WRITE    0x02
  462. #define    IO_WORD        0x01
  463.  
  464. STATIC int
  465. V86IOEmulate(
  466.     byte_t    op,
  467.     word_t    io_addr
  468.     )
  469. {
  470.     register struct tss386    *t    = v86tss;
  471.     static    unsigned    cmos_addr;
  472.  
  473.     switch (io_addr)
  474.     {
  475.     case 0x20:    /* master PIC command port    */
  476.         if ((op & ~0x08) == 0xe4 && AL(t) == 0x20)
  477.         return 1;
  478.  
  479.     case 0x70:
  480.         if (op & IO_WRITE)
  481.         {
  482.         cmos_addr = AL(t);
  483.         if (op & IO_WORD)
  484.             cmos_write(cmos_addr, AH(t));
  485.         }
  486.         else
  487.         {
  488.         AL(t) = cmos_addr;
  489.         if (op & IO_WORD)
  490.             AH(t) = cmos_read(cmos_addr);
  491.         }
  492.         return 1;
  493.  
  494.     case 0x71:
  495.         if (op & IO_WRITE)
  496.         cmos_write(cmos_addr, AL(t));
  497.         else
  498.         AL(t) = cmos_read(cmos_addr);
  499.  
  500.         return 1;
  501.  
  502.     default:
  503.         if (op & IO_WRITE)
  504.         fatal(0, "illegal i/o write of %4x to %4x, cs:ip = %4x:%4x\n",
  505.             (op & IO_WORD) ? AX(t) : AL(t), io_addr, CS(t), IP(t));
  506.         else
  507.         fatal(0, "illegal i/o read from %4x, cs:ip = %4x:%4x\n",
  508.             io_addr, CS(t), IP(t));
  509.     }
  510.  
  511.     return 0;
  512. }
  513.  
  514. static int    cmos_fd    = -1;
  515.  
  516. cmos_write(
  517.     unsigned    addr,
  518.     unsigned    data
  519.     )
  520. {
  521.     fatal(0, "illegal write to CMOS, addr = %02x, data = %02x\n",
  522.     addr, data);
  523. }
  524.  
  525. cmos_read(
  526.     unsigned    addr
  527.     )
  528. {
  529.     unsigned char    data;
  530.  
  531.     if (cmos_fd < 0)
  532.     cmos_fd = open("/dev/cmos", 0);
  533.  
  534.     if (addr >= CMOSSIZE)
  535.     return 0;
  536.  
  537.     if (cmos_fd < 0 || lseek(cmos_fd, (long)addr, 0) != (long) addr 
  538.     || read(cmos_fd, &data, 1) != 1)
  539.     fatal(errno, "read from CMOS addr %02x failed\n", addr);
  540.  
  541.     return data;
  542. }
  543.  
  544. char *
  545. V86ErrorMessage(
  546.     int        r
  547.     )
  548. {
  549.     register struct tss386    *t    = v86tss;
  550.     static char    message[80];
  551.     char    *p;
  552.  
  553.     switch (r)
  554.     {
  555.     case ERR_V86_HALT:
  556.         p    = "halt instruction";
  557.         break;
  558.     case ERR_V86_DIV0:
  559.         p    = "divide by zero trap";
  560.         break;
  561.     case ERR_V86_SGLSTP:
  562.         p    = "single step trap";
  563.         break;
  564.     case ERR_V86_BRKPT:
  565.         p    = "breakpoint trap";
  566.         break;
  567.     case ERR_V86_OVERFLOW:
  568.         p    = "overflow trap";
  569.         break;
  570.     case ERR_V86_BOUND:
  571.         p    = "bounds trap";
  572.         break;
  573.     case ERR_V86_ILLEGAL_OP:
  574.         p    = "illegal instruction trap";
  575.         break;
  576.     case ERR_V86_ILLEGAL_IO:
  577.         p    = "illegal i/o";
  578.         break;
  579.     }
  580.  
  581.     sprintf(message, "%s at %04x:%04x", p, CS(t), IP(t));
  582.  
  583.     return message;
  584. }
  585.  
  586. /*ARGSUSED*/
  587. v86debug(
  588.     int        type,        /* debug type                */
  589.     char    *fmt,        /* message format string        */
  590.     ...                /* optional arguments            */
  591.     )
  592. {
  593.     va_list    args;
  594.  
  595.     va_start(args, fmt);
  596.     (void) vfprintf(stderr, fmt, args);
  597.     va_end(args);
  598. }
  599.